using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

using LowLevelGraphics;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// 
    /// </summary>
    public class SaliencyMap : BaseImageFilter
    {
        /// <summary>
        /// 
        /// </summary>
        public SaliencyMap()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_saliencyMap"></param>
        internal SaliencyMap(SaliencyMap _SaliencyMap)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            float a = 0;
            float r = 0;
            float g = 0;
            float b = 0;

            float I = 0;
            float R = 0;
            float G = 0;
            float B = 0;
            float Y = 0;
            float rn = 0;
            float gn = 0;
            float bn = 0;
            float H = 0;
            float S = 0;
            float RG = 0;
            float BY = 0;

            int x = 0;
            int y = 0;
            int nWidth = _bitmap.Width;
            int nHeight = _bitmap.Height;

            float[,] cConspicuity = new float[nWidth, nHeight]; //color map
            float[,] iConspicuity = new float[nWidth, nHeight]; //intensity map
            float[,] oConspicuity = new float[nWidth, nHeight]; //orientation map
            float[,] mConspicuity = new float[nWidth, nHeight]; //motion map
          
            //Create oriented Gabor maps
            //int[] aAngle = new int[] { 0, 45, 90, 135 };
            //UnsafeBitmap[] aGabor = new UnsafeBitmap[aAngle.Length];
            //int i=0;
            //for (i = 0; i < aAngle.Length; i++)
            //{
            //    Gabor gabor = new Gabor();
            //    gabor.Orientation = aAngle[i];
            //    UnsafeBitmap bitmapGabor = (UnsafeBitmap)_bitmap.Clone();
            //    aGabor[i] = gabor.ExecuteCloned(bitmapGabor);
            //}
            //for (y = 0; y < nHeight; y++)
            //{
            //    for (x = 0; x < nWidth; x++)
            //    {
            //        for (i = 1; i < aAngle.Length; i++)
            //        {
            //            int nValue1 = aGabor[i-1].GetPixel(x, y).R;
            //            int nValue2 = aGabor[i].GetPixel(x, y).R;
            //            oConspicuity[x, y] = (float)Math.Max(nValue1, nValue2);
            //        }
            //    }
            //}

            UnsafeBitmap bitmapGaussian = (UnsafeBitmap)_bitmap.Clone();

            for (int i = 0; i < 4; i++)
            {
                new GaussianBlur().Execute(bitmapGaussian).Dispose();
                bitmapGaussian = new UnsafeBitmap(bitmapGaussian.InternalBitmap, new Size(bitmapGaussian.Width / 2, bitmapGaussian.Height / 2));
            }

            //First step: Feature maps
            //Features inhibition...
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    Color color = _bitmap.GetPixel(x, y);
                    r = (float)color.R;
                    g = (float)color.G;
                    b = (float)color.B;

                    //Intensity feature (Feature 1)
                    I = (r + g + b) / 3;

                    //Four Color channels (Feature 2, 3, 4, 5)
                    //Four color channels are created, such as red, green, blue, and yellow: 
                    R = r - (g + b) / 2;
                    G = g - (r + b) / 2;
                    B = b - (r + g) / 2;
                    Y = (r + g) / 2 - Math.Abs(r - g) / 2 - b;
                    //H = 1/360*(90-Definitions.Ar;
                    S = 1 - (Min(R, G, B) / I);
                    //Then each two chromatic features are computed by the 
                    //opponent filters (Feature 5,6)
                    RG = Math.Abs(R - G);
                    BY = Math.Abs(B - Y);

                    rn = r / (r + b + g);
                    gn = g / (r + b + g);
                    bn = b / (r + b + g);

                    cConspicuity[x, y] = Max(R, G, B, Y);
                    cConspicuity[x, y] = ImageMath.Clamp(cConspicuity[x, y], 0, 255);
                    iConspicuity[x, y] = I;

                    //Local orientation features are obtained from  I using oriented Gabor pyramids O( ) ?
                    //, where ? ?{0 , 45 , 90 ,135 }D D D  D is the preferred or on.  ienta (Feature 7)
                    _bitmap.SetGrayPixel(x, y, (int)(cConspicuity[x, y] + iConspicuity[x, y]) / 2);
                    Color[] aColor = new Color[8];
                    color = _bitmap.GetPixel(x, y);

                    aColor = Segmentation.GetEnvironmentPixelColorArray(_bitmap, x, y, Definitions.EnvironmentPointListClockwise, aColor);
                    int nSum = 0;
                    foreach (Color colorTemp in aColor)
                    {
                        nSum += (int)((colorTemp.R + colorTemp.G + colorTemp.B) / 3.0f);
                    }
                    int nValue = (int)Math.Abs(nSum / 8 - I);
                    _bitmap.SetGrayPixel(x, y, nValue);
                }
            }

            
            //Conspicuity maps

            //Linear combination

            //The static saliency map 
            //
            //Finally, three feature conspicuity maps are combined into the 
            //static saliency map
            //The integration can be computed as 
            //S = 1/3 *( N(I)+N(C)+N(O) )

            //Dynamic Saliency Map
            //S = ws Ss + wD Sd
            //Here, the weight ws and  are set 1
    
            return _bitmap;
        }

        public float Max(params float[] _aValue)
        {
            float val = _aValue[0];
            for (int i = 1; i < _aValue.Length; i++)
            {
                val = Math.Max(val, _aValue[i]);
            }
            return val;
        }

        public float Min(params float[] _aValue)
        {
            float val = _aValue[0];
            for (int i = 1; i < _aValue.Length; i++)
            {
                val = Math.Min(val, _aValue[i]);
            }
            return val;
        }

        /// <summary>
        /// Clones this instance
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new SaliencyMap(this);
        }
    }
}
